package com.wutma.system.service.exam.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.wutma.common.core.constants.Constants;
import com.wutma.common.core.enums.ResultCode;
import com.wutma.common.security.exception.ServiceException;
import com.wutma.system.domain.exam.dto.ExamAddDTO;
import com.wutma.system.domain.exam.dto.ExamEditDTO;
import com.wutma.system.domain.exam.dto.ExamQueryDTO;
import com.wutma.system.domain.exam.dto.ExamQuestionAddDTO;
import com.wutma.system.domain.exam.entity.Exam;
import com.wutma.system.domain.exam.entity.ExamQuestion;
import com.wutma.system.domain.exam.vo.ExamDetailVO;
import com.wutma.system.domain.exam.vo.ExamVO;
import com.wutma.system.domain.question.entity.Question;
import com.wutma.system.domain.question.vo.QuestionVO;
import com.wutma.system.manager.ExamCacheManager;
import com.wutma.system.mapper.exam.ExamMapper;
import com.wutma.system.mapper.exam.ExamQuestionMapper;
import com.wutma.system.mapper.question.QuestionMapper;
import com.wutma.system.service.exam.ExamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
public class ExamServiceImpl extends ServiceImpl<ExamQuestionMapper, ExamQuestion> implements ExamService {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamQuestionMapper examQuestionMapper;

    @Autowired
    private ExamCacheManager examCacheManager;

    @Override
    public List<ExamVO> list(ExamQueryDTO examQueryDTO) {

        PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
        parseToLocalDateTime(examQueryDTO);
        return examMapper.selectExamList(examQueryDTO);
    }

    @Override
    public String add(ExamAddDTO examAddDTO) {

        checkExamSaveParams(examAddDTO, null);
        Exam exam = new Exam();
        BeanUtil.copyProperties(examAddDTO, exam);
        examMapper.insert(exam);
        return exam.getExamId().toString();
    }

    private void parseToLocalDateTime(ExamQueryDTO examQueryDTO) {

        if (StrUtil.isEmpty(examQueryDTO.getStartTime()) && StrUtil.isEmpty(examQueryDTO.getEndTime())) {
            return;
        }
        try {
            // 解析 ISO 8601 格式时间
            examQueryDTO.setStartTime(OffsetDateTime.parse(
                    examQueryDTO.getStartTime(),
                    DateTimeFormatter.ISO_OFFSET_DATE_TIME).toLocalDateTime().toString());
            examQueryDTO.setEndTime(OffsetDateTime.parse(
                    examQueryDTO.getEndTime(),
                    DateTimeFormatter.ISO_OFFSET_DATE_TIME).toLocalDateTime().toString());
        } catch (Exception e) {
            throw new ServiceException(ResultCode.FAILED_QUERY_TIME);
        }
    }

    private void checkExamSaveParams(ExamAddDTO examSaveDTO, Long examId) {
        // 检查竞赛标题是否重复，开始时间、结束时间是否有误
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .eq(Exam::getTitle, examSaveDTO.getTitle())
                .ne(examId != null, Exam::getExamId, examId));
        if (CollectionUtil.isNotEmpty(examList)) {
            throw new ServiceException(ResultCode.FAILED_ALREADY_EXISTS);
        }
        if (examSaveDTO.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_START_TIME_BEFORE_CURRENT_TIME);
        }
        if (examSaveDTO.getEndTime().isBefore(examSaveDTO.getStartTime())) {
            throw new ServiceException(ResultCode.EXAM_START_TIME_AFTER_END_TIME);
        }
    }

    @Override
    public boolean questionAdd(ExamQuestionAddDTO examQuestionAddDTO) {

        Exam exam = getExam(examQuestionAddDTO.getExamId());
        checkExamPublish(exam);
        checkExamStart(exam);
        // 判断提交的竞赛题目是否全部存在
        Set<Long> questionIdSet = examQuestionAddDTO.getQuestionIdSet();
        if (CollectionUtil.isEmpty(questionIdSet)) {
            // 为空表示没有添加题目，正常返回
            return true;
        }
        List<Question> questionList = questionMapper.selectBatchIds(questionIdSet);
        if (CollectionUtil.isEmpty(questionList) || questionList.size() < questionIdSet.size()) {
            throw new ServiceException(ResultCode.EXAM_QUESTION_NOT_EXISTS);
        }

        // 将所有指定题目添加到当前竞赛题库中
        return saveExamQuestions(exam, questionIdSet);
    }

    @Override
    public ExamDetailVO detail(Long examId) {
        // 1. 获取竞赛初始详情信息
        Exam exam = getExam(examId);
        ExamDetailVO examDetailVO = new ExamDetailVO();
        BeanUtil.copyProperties(exam, examDetailVO);
//        // 2. 查询当前竞赛题库的所有题目Id
//        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(new LambdaQueryWrapper<ExamQuestion>()
//                .select(ExamQuestion::getQuestionId)
//                .eq(ExamQuestion::getExamId, examId)
//                .orderByAsc(ExamQuestion::getQuestionOrder));
//        if (CollectionUtil.isEmpty(examQuestionList)) {
//            // 若竞赛题库为空，直接返回
//            return examDetailVO;
//        }
        // 3. 通过题目Id获取指定内容
        // 3.1 过滤其它空内容，只留Id
//        List<Long> questionIdList = examQuestionList.stream().map(ExamQuestion::getQuestionId).toList();
        // 3.2 通过Id到题目表查询其它内容
//        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>()
//                .select(Question::getQuestionId, Question::getTitle, Question::getDifficulty)
//                .in(Question::getQuestionId, questionIdList));
//        List<QuestionVO> questionVOList = BeanUtil.copyToList(questionList, QuestionVO.class);
        List<QuestionVO> questionVOList = examQuestionMapper.selectExamQuestionList(examId);
        if (CollectionUtil.isEmpty(questionVOList)) {
            return examDetailVO;
        }
        // 3.3 将竞赛题目列表赋值返回
        examDetailVO.setExamQuestionList(questionVOList);
        return examDetailVO;
    }

    @Override
    public int edit(ExamEditDTO examEditDTO) {
        
        Exam exam = getExam(examEditDTO.getExamId());
        checkExamPublish(exam);
        checkExamStart(exam);
        checkExamSaveParams(examEditDTO, exam.getExamId());
        exam.setTitle(examEditDTO.getTitle());
        exam.setStartTime(examEditDTO.getStartTime());
        exam.setEndTime(examEditDTO.getEndTime());
        return examMapper.updateById(exam);
    }

    @Override
    public int delete(Long examId) {
        Exam exam = getExam(examId);
        checkExamPublish(exam);
        checkExamStart(exam);
        examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId));
        return examMapper.deleteById(examId);
    }

    @Override
    public int publish(Long examId) {
        Exam exam = getExam(examId);
        if (exam.getEndTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_HAS_FINISHED);
        }
        Long count = examQuestionMapper.selectCount(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId));
        if (count == null || count <= 0) {
            throw new ServiceException(ResultCode.EXAM_HAS_NOT_QUESTION);
        }
        exam.setStatus(Constants.TRUE);
        examCacheManager.addCache(exam);
        return examMapper.updateById(exam);
    }

    @Override
    public int cancelPublish(Long examId) {
        Exam exam = getExam(examId);
        if (exam.getEndTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_HAS_FINISHED);
        }
        checkExamStart(exam);
        exam.setStatus(Constants.FALSE);
        examCacheManager.deleteCache(examId);
        return examMapper.updateById(exam);
    }

    @Override
    public int questionDelete(Long examId, Long questionId) {

        Exam exam = getExam(examId);
        checkExamStart(exam);
        return examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId)
                .eq(ExamQuestion::getQuestionId, questionId));
    }


    private void checkExamPublish(Exam exam) {
        if (Constants.TRUE.equals(exam.getStatus())) {
            throw new ServiceException(ResultCode.EXAM_IS_PUBLISH);
        }
    }

    private void checkExamStart(Exam exam) {
        if (exam.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_STARTED);
        }
    }

    private Exam getExam(Long examId) {
        // 判断当前竞赛是否存在
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.EXAM_NOT_EXISTS);
        }
        return exam;
    }

    private boolean saveExamQuestions(Exam exam, Set<Long> questionIdSet) {

        List<ExamQuestion> examQuestionList = new ArrayList<>();
        int order = 1;
        for (Long questionId : questionIdSet) {
            ExamQuestion examQuestion = new ExamQuestion();
            examQuestion.setExamId(exam.getExamId());
            examQuestion.setQuestionId(questionId);
            examQuestion.setQuestionOrder(order++);
            examQuestionList.add(examQuestion);
        }
        return saveBatch(examQuestionList);
    }
}
